package net.gdface.cassdk;

import java.util.List;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import android.graphics.Bitmap;
import net.gdface.image.ImageErrorException;
import net.gdface.image.LazyImage;
import net.gdface.license.LicenseManager;
import net.gdface.sdk.BaseFaceApiLocal;
import net.gdface.sdk.CodeInfo;
import net.gdface.sdk.FaceApiGenericDecorator;
import net.gdface.sdk.NotFaceDetectedException;
import net.gdface.sdk.fse.FeatureSe;
import net.gdface.utils.ShareLock;

import static net.gdface.cassdk.CasAndroidConfigProvider.*;

/**
 * CASSDK android/arm平台 {@link net.gdface.sdk.FaceApi}接口实现类(线程安全)<br>
 * 基于commons-pools将非线程安全的{@link CasAndroidArmBridge}实例用资源池{@link GenericObjectPool}管理,
 * 每次调用前从资源池申请一个{@link CasAndroidArmBridge}实例来使用，用完后归还资源池，
 * 以实现对{@link CasAndroidArmBridge}实例线程安全的调用
 * @author guyadong
 *
 */
public class FaceApiCasAndroid extends BaseFaceApiLocal {
	private static final FaceApiCasAndroid INSTANCE = new FaceApiCasAndroid();
	private static final FaceApiGenericDecorator GENERIC_INSTANCE = new FaceApiGenericDecorator(INSTANCE);
	/**
	 * 用于人脸检测的数据缓冲区
	 */
	private static final ThreadLocal<double[]> faceBuffer = new ThreadLocal<double[]>(){

		@Override
		protected double[] initialValue() {
			return new double[FDDATA_LEN*MAX_FACE_COUNT];
		}		
	};
	protected FaceApiCasAndroid() {
	}
	/**
	 * 返回单实例
	 * @return the instance
	 */
	public static FaceApiCasAndroid getInstance() {
		return INSTANCE;
	}
	/**
	 * 返回支持泛型封闭的单实例
	 * @return
	 */
	public static FaceApiGenericDecorator getGenericInstance(){
		return GENERIC_INSTANCE;
	}
	/**
	 * @return 返回SDK的授权信息管理实例
	 */
	public static LicenseManager licenseManager(){
		return CasAndroidArmBridge.LICENSE_MANAGER;
	}
	@Override
	public final String sdkVersion() {
		return CasAndroidArmBridge.SDK_VERSION;
	}
	@Override
	protected double nativeCompareCode(byte[] code1, byte[] code2) {
		return CasAndroidArmBridge.FFSimilarityByte(code1,code2);
	}

	@Override
	public void nativeDetectFace(byte[] imgMatrix, int width, int height, List<CodeInfo> faceInfo) {
		double[] buffer = faceBuffer.get();
		CasAndroidArmBridge instance = applyInstance();
		try{
			int res = instance.detect(imgMatrix, width, height, buffer);
			for(int i=0; i < res; ++i){
				faceInfo.add(new NativeFaceInfo(buffer, i*FDDATA_LEN));
			}
		}finally {
			returnInstance(instance);
		}
	}

	@Override
	public byte[] nativeGetFaceFeature(byte[] imgMatrix, int width, int height, CodeInfo faceInfo) {
		NativeFaceInfo nativeFaceInfo = NativeFaceInfo.toNative(faceInfo);
		CasAndroidArmBridge instance = applyInstance();
		try{
			return instance.feaExtractByte(imgMatrix, width, height, nativeFaceInfo.nativeData);
		}finally{
			returnInstance(instance);
		}
	}
	/**
	 * 检测人脸
	 * @param bitmap
	 * @return
	 */
	public List<CodeInfo> detectFace(Bitmap bitmap){
		try {
			return detectFace(LazyImage.create(bitmap));
		} catch (ImageErrorException e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 提取特征
	 * @param bitmap
	 * @param faceNum
	 * @param facePos
	 * @return
	 * @throws NotFaceDetectedException
	 */
	public List<CodeInfo> getCodeInfo(Bitmap bitmap, int faceNum, List<CodeInfo> facePos) 
			throws NotFaceDetectedException{
		return getCodeInfo(LazyImage.create(bitmap), faceNum, facePos);
	}
	/**
	 * 提取单个人脸特征 
	 * @param bitmap
	 * @param facePos
	 * @return
	 */
	public CodeInfo getCodeInfo(Bitmap bitmap, CodeInfo facePos){
		return getCodeInfo(LazyImage.create(bitmap), facePos);
	}
	/**
	 * 检测并提取人脸特征
	 * @param bitmap
	 * @param faceNum
	 * @return
	 * @throws NotFaceDetectedException
	 */
	public CodeInfo[] detectAndGetCodeInfo(Bitmap bitmap, int faceNum) 
			throws NotFaceDetectedException {
		try {
			return detectAndGetCodeInfo(LazyImage.create(bitmap).open(), faceNum);
		} catch (ImageErrorException e) {
			throw new RuntimeException(e);
		}
	}
	@Override
	public FeatureSe getFeatureSe() {
		return FseAndroidBridge.getFeatureSe();
	}
	/**
	 * {@link CasAndroidArmBridge}实例资源池<br>
	 * 每一次执行SDK调用时，要从资源池从申请一个{@link CasAndroidArmBridge}实例，调用结束后归还到资源池，
	 * 实例的初始化和销毁都由资源负责，调用者不须负责{@link CasAndroidArmBridge}实例的初始化与释放
	 */
	private static final GenericObjectPool<CasAndroidArmBridge> pool;
	static {
	
		// 资源池初始化
		GenericObjectPoolConfig config = new GenericObjectPoolConfig();
		// android平台不支持JMX,所以这里必须设置为false,否则抛出异常
		config.setJmxEnabled(false);
		pool = new GenericObjectPool<CasAndroidArmBridge>(new BridgeInstanceFactory(),config);
		
		// 根据配置参数设置并发线程数
		int concurrenty = CasAndroidArmBridge.CONFIG.getConcurrency();
		if(concurrenty > 0){
			concurrentLock = new ShareLock(concurrenty);
		}
	}
	/**
	 * 从资源池申请一个实例
	 * @return
	 * @throws SdkRuntimeException SDK初始化失败
	 */
	private static CasAndroidArmBridge applyInstance() throws SdkRuntimeException {
		try {
			return pool.borrowObject();
		} catch(SdkInitException e){
			throw new SdkRuntimeException(e);
		} catch(RuntimeException e){
			throw e;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 归还实例到资源池
	 * @param obj
	 */
	private static void returnInstance(CasAndroidArmBridge obj) {
		pool.returnObject(obj);
	}
}
